/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-09-14 14:16:26
 * @LastEditTime: 2021-10-09 09:16:58
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "strto.h"
#include "generic_timer.h"
#include "sdkconfig.h"
#ifndef SDK_CONFIG_H__
    #warning "Please include sdkconfig.h"
#endif
#include "ft_debug.h"
#include "parameters.h"
#include "../src/shell.h"
#include "sdmmc_app.h"

static sdmmc_host_t sdmmc_host;
static sdmmc_card_t sdmmc_card;
static FSdmmcCtrl sdmmc_ctrl;
static char read_buf[FSDMMC_DEF_BLK_SIZE * FSDMMC_MAX_BLK_TRANS];
static char write_buf[FSDMMC_DEF_BLK_SIZE * FSDMMC_MAX_BLK_TRANS];

static int MmcInit()
{
    memset(&sdmmc_host, 0, sizeof(sdmmc_host));
    memset(&sdmmc_card, 0, sizeof(sdmmc_card));
    memset(&sdmmc_ctrl, 0, sizeof(sdmmc_ctrl));

    if (FT_COMPONENT_IS_READY == sdmmc_ctrl.is_ready)
    {
        return 0;
    }

    sdmmc_host_config(FSDMMC_HOST_INSTANCE_0, &sdmmc_host, &sdmmc_card, &sdmmc_ctrl);
    if (SDMMC_OK != sdmmc_host_init())
    {
        printf("sdmmc host init failed\r\n");
        return -1;
    }

    return 0;
}

static int MmcSetString(const char *string, u32 blk)
{
    memset(write_buf, 0, FSDMMC_DEF_BLK_SIZE);
    memcpy(write_buf, string, strlen(string) + 1);
    return sdmmc_host_write_sectors(&sdmmc_host, blk, 1, write_buf);
}

static int MmcGetString(u32 blk)
{
    int ret;

    memset(read_buf, 0 , FSDMMC_DEF_BLK_SIZE);
    ret = sdmmc_host_read_sectors(&sdmmc_host, blk, 1, read_buf);
    if (0 == ret)
        FtDumpHexByte(read_buf, FSDMMC_DEF_BLK_SIZE);

    return ret;
}

static int MmcWrite(u32 blk, u32 blk_num, char *strs[], int str_num)
{
    int i;
    int ret;

    printf("num: %d, str1: %s, str2: %s\r\n", str_num, strs[0], strs[1]);

    memset(write_buf, 0, FSDMMC_DEF_BLK_SIZE * FSDMMC_MAX_BLK_TRANS);
    for (i = 0; i < str_num; i++)
    {
        memcpy(write_buf + i * FSDMMC_DEF_BLK_SIZE, strs[i], strlen(strs[i]) + 1);
    }

    ret = sdmmc_host_write_sectors(&sdmmc_host, blk, blk_num, write_buf);
    return ret;
}

static int MmcPattern(u32 blk, u32 blk_num, char *pattern)
{
    int i;
    int ret;
    size_t pattern_len = strlen(pattern) + 1;
    size_t buf_len = blk_num * FSDMMC_DEF_BLK_SIZE;
    uintptr buf_p = 0;

    while (buf_p < buf_len)
    {
        if (buf_len > pattern_len)
        {
            memcpy(write_buf + buf_p, pattern, pattern_len);
            buf_p += pattern_len;
        }
        else
        {
            memcpy(write_buf + buf_p, pattern, buf_len);
            buf_p = buf_len;
        }
    }

    ret = sdmmc_host_write_sectors(&sdmmc_host, blk, blk_num, write_buf);
    return ret;
}

static int MmcRead(u32 blk, u32 blk_num)
{
    int ret;

    if (FSDMMC_MAX_BLK_TRANS< blk_num)
        return -4;

    memset(read_buf, 0, FSDMMC_DEF_BLK_SIZE * FSDMMC_MAX_BLK_TRANS);
    ret = sdmmc_host_read_sectors(&sdmmc_host, blk, blk_num, read_buf);
    if (0 == ret)
        FtDumpHexByte(read_buf, FSDMMC_DEF_BLK_SIZE * blk_num);
    
    return ret;
}

static void MmcUsage()
{
	printf("usage:\r\n");
	printf("    mmc probe\r\n");
    printf("        -- print mmcsd card info\r\n");    
    printf("    mmc set [target_blk] [string]\r\n");
    printf("        -- set a string to target mmc block\r\n");
    printf("    mmc get [source_blk]\r\n");
    printf("        -- get a string from source mmc block\r\n");
    printf("    mmc read [start_blk] [blk_num] \r\n");
    printf("        -- read blk_num blocks from start_blk\r\n");
    printf("    mmc write [start_blk] [blk_num] [string] \r\n");
    printf("        -- write blk_num blocks from start_blk with the same string\r\n");
    printf("    mmc pattern [start_blk] [blk_num] [string] \r\n");
    printf("        -- fill blk_num blocks from start_blk with pattern string\r\n");
}

static int MmcCmdEntry(int argc, char *argv[])
{
    u32 err = FSDMMC_SUCCESS;
	u32 blk, cnt, align;
	void *addr;
    char *str;
    int ret = 0;

    if(argc < 2)
	{
		MmcUsage();
        return -1;
	}

    /* init sdmmc ctrl if not ready */
    if (0 != MmcInit())
    {
        return -1;
    }

    if(!strcmp(argv[1], "probe"))
    {
        
    }
    else if (!strcmp(argv[1], "read"))
    {
        if(argc < 4)
        {
            MmcUsage();
            return -1;
        }

        blk = simple_strtoul(argv[2], NULL, 16);
        cnt = simple_strtoul(argv[3], NULL, 16);        
        return MmcRead(blk, cnt);
    }
    else if (!strcmp(argv[1], "write"))
    {
        if(argc < 5)
        {
            MmcUsage();
            return -1;
        }

        blk = simple_strtoul(argv[2], NULL, 16);
        cnt = simple_strtoul(argv[3], NULL, 16);
        return MmcWrite(blk, cnt, &argv[4], argc - 4);    
    }
    else if (!strcmp(argv[1], "set"))
    {
        if(argc < 4)
        {
            MmcUsage();
            return -1;
        }

        blk = simple_strtoul(argv[2], NULL, 16);
        str = argv[3];
        ret = MmcSetString(str, blk);
    }
    else if (!strcmp(argv[1], "get"))
    {
        if(argc < 3)
        {
            MmcUsage();
            return -1;
        }

        blk = simple_strtoul(argv[2], NULL, 16);
        ret = MmcGetString(blk);
    }
    else if (!strcmp(argv[1], "pattern"))
    {
        if (argc != 5)
        {
            MmcUsage();
            return -1;            
        }

        blk = simple_strtoul(argv[2], NULL, 16);
        cnt = simple_strtoul(argv[3], NULL, 16);
        return MmcPattern(blk, cnt, argv[4]);
    }

    return ret;
}
SHELL_EXPORT_CMD(SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), mmc, MmcCmdEntry, test sdmmc driver);